#ifndef __SUBSYSTEM_HPP__
#define __SUBSYSTEM_HPP__

#include "nlohmann/json.hpp"
#include <string>
#include "entt/entt.hpp"
#include "Utils/Utils.h"

#include "SimpleSingleton.hpp"

namespace PocketSurvival
{
    // 加载梯队，越前的越早加载，可由此来设置加载顺序
    enum class SubLoadEchelon
    {
        First,
        Second,
        Third,
        Fourth,
        Fifth,
        Sixth,
        Seventh,
        Eighth,
        Ninth,
        Tenth,
    };

    enum class SubUpdateType
    {
        NoUpdate,               // 不需要调用 update 函数
        MainSingleUpdate,       // 主线程调用 update 函数
        MultiThreadUpdate,      // 多线程调用 update 函数
    };

    class TerrainChunk;

    class Subsystem : public SimpleSingletonItem
    {
        friend class SimpleSingleton;
    protected:
        constexpr explicit Subsystem() noexcept;
        inline virtual ~Subsystem();

    public:
        Subsystem(const Subsystem &) = delete;
        Subsystem(Subsystem &&) = delete;
        Subsystem &operator=(const Subsystem &) = delete;
        Subsystem &operator=(Subsystem &&) = delete;
        
        inline virtual void onEntityAdded(entt::entity entity);
        inline virtual void onEntityRemoved(entt::entity entity);
        inline virtual void onTerrainChunkAdded(TerrainChunk *terrainChunk);
        inline virtual void onTerrainChunkRemoved(TerrainChunk *terrainChunk);
        
        inline virtual void update(float dt);
        inline virtual void load(const nlohmann::json &json);
        inline virtual void save(nlohmann::json &json);
        inline virtual void saveToMsgJson(nlohmann::json &jsonData);

        virtual const std::string &getName() const = 0;
        inline virtual SubLoadEchelon getLoadEchelon();
        inline virtual SubUpdateType getUpdateType();
    };

    constexpr inline Subsystem::Subsystem() noexcept {}
    inline Subsystem::~Subsystem() {}

    inline void Subsystem::onEntityAdded(entt::entity entity) {}
    inline void Subsystem::onEntityRemoved(entt::entity entity) {}
    inline void Subsystem::onTerrainChunkAdded(TerrainChunk *terrainChunk) {}
    inline void Subsystem::onTerrainChunkRemoved(TerrainChunk *terrainChunk) {}

    inline void Subsystem::update(float dt) {}
    inline void Subsystem::load(const nlohmann::json &json) {}
    inline void Subsystem::save(nlohmann::json &json) {}
    inline void Subsystem::saveToMsgJson(nlohmann::json &jsonData) {}

    inline SubLoadEchelon Subsystem::getLoadEchelon()
    {
        return SubLoadEchelon::First;
    }
    inline SubUpdateType Subsystem::getUpdateType()
    {
        return SubUpdateType::NoUpdate;
    }
}

#endif